﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Configuration;
using Common.Logging;
using Crawler.Data;

namespace Crawler.Stuff
{
    public class Growth
    {
        private DataDataContext dc;
        private ILog log;
        private int lastPostion = int.Parse(WebConfigurationManager.AppSettings["LastPostion"]);

        public Growth()
        {
            dc = new DataDataContext();
            log = LogManager.GetCurrentClassLogger();
        }

        public int UpdateAppGrowth(DateTime parsingDay)
        {
            int i = 0;
            foreach (var app in dc.Apps.OrderByDescending(a => a.Id))
            {
                //проверяем добавлялись ли статы для этого приложения в данный день
                //TODO: Nullable тип => обычный тип
                if (
                    (from g in dc.AppGrowths
                     where g.AppId == app.Id && g.ParsingDate.Value.Date == parsingDay.Date 
                     select g).Count() == 0)
                {
                    //пытаемя взять поседний стат
                    var lastStat = app.AppStats.OrderBy(s => s.ParsingDate).FirstOrDefault();
                    if (lastStat != null) //нет статов вообще - ничего не делаем
                    {
                        AppStat appStat;
                        // если есть статы с позицией им отдается приоритет
                        var appStats = app.AppStats.Where(s => s.ParsingDate.Date == parsingDay.Date);
                        if (appStats.Where(s => s.Position != lastPostion).Count() != 0)
                        {
                            appStat =
                                appStats.Where(s => s.Position != lastPostion).OrderByDescending(s => s.ParsingDate).First();
                        }
                        else
                        {
                            appStat = appStats.OrderByDescending(s => s.ParsingDate).FirstOrDefault();
                        }
                        if (appStat != null) //если их нет то и роста не будет
                        {
                            var dailyStat = GetDailyStat(app, parsingDay, lastStat);
                            var wStat = GetWeeklyStat(app, parsingDay, lastStat);
                            var mStat = GetMonthlyStat(app, parsingDay, lastStat);
                            var appGrowth = new AppGrowth();
                            if (dailyStat != null)
                            {
                                appGrowth.DailyUsersGrowth = appStat.Users - dailyStat.Users;
                                appGrowth.DailyPositionGrowth = CalculatePositionsGrowth(appStat, dailyStat);
                                appGrowth.DailyPercentageGrowth = (decimal)appGrowth.DailyUsersGrowth / appStat.Users;
                            }
                            if (wStat != null)
                            {
                                appGrowth.WeklyUsersGrowth = appStat.Users - wStat.Users;
                                appGrowth.WeeklyPositionGrowth = CalculatePositionsGrowth(appStat, wStat);
                                appGrowth.WeeklyPercentageGrowth = (decimal)appGrowth.WeklyUsersGrowth / appStat.Users;
                            }
                            if (mStat != null)
                            {
                                appGrowth.MonthlyPositionGrows = CalculatePositionsGrowth(appStat, mStat);
                                appGrowth.MothlyUsersGrowth = appStat.Users - mStat.Users;
                                appGrowth.MonthlyPercentageGrowth = (decimal)appGrowth.MothlyUsersGrowth / appStat.Users;
                            }
                            if (dailyStat != null || wStat != null || mStat != null)
                            {
                                appGrowth.App = app;
                                appGrowth.Users = appStat.Users;
                                appGrowth.ParsingDate = appStat.ParsingDate;
                                appGrowth.Position = appStat.Position;
                                appGrowth.AppStatId = appStat.Id;
                                dc.AppGrowths.InsertOnSubmit(appGrowth);
                                i++;
                                log.DebugFormat("Inserting {0} appgrowth", i);
                            }
                            else
                            {
                                log.DebugFormat("all growth are null for appId {0}", app.Id);
                            }
                        }
                        else
                        {
                            log.DebugFormat("No current stats for appid {0}", app.Id);
                        }
                    }
                    else
                    {
                        log.DebugFormat("No last stats for appid {0}", app.Id);
                    }
                    dc.SubmitChanges();
                }
                else
                {
                    log.DebugFormat("Growth for appid {0} already added thi day", app.Id);
                }
            }
            log.DebugFormat("Job finifshed. {0} appgrowth inserted", i);
            return i;
        }

        public int CalculatePositionsGrowth(AppStat curStat, AppStat lastStat)
        {
            if(lastStat.Position == -1 && curStat.Position == -1)
            {
                return 0;
            }
            if(lastStat.Position == -1)
            {
                return 1000 - curStat.Position;
            }
            if(curStat.Position == -1)
            {
                return lastStat.Position - 1000;
            }
            return lastStat.Position - curStat.Position;
        }

        /// <summary>
        /// Берем статы за прошлый день, если таких нет но есть раньше берем их
        /// </summary>
        /// <param name="app"></param>
        /// <param name="parsigDay"></param>
        /// <param name="lastStat"></param>
        /// <returns></returns>
        private AppStat GetDailyStat(App app, DateTime parsigDay, AppStat lastStat)
        {
            // есть статы на день раньше данного дня
            if (parsigDay.Date.AddDays(-1) > lastStat.ParsingDate.Date) 
            {
                var stats = app.AppStats
                    .Where(s => s.ParsingDate <= parsigDay.AddDays(-1)) //берем прошлый день или раньше
                    .OrderByDescending(s => s.ParsingDate);
                //приоритет стату с позицией
                var posStat = stats.Where(s => s.Position != -1).FirstOrDefault();
                if (posStat == null)
                {
                    return stats.FirstOrDefault();
                }
                return posStat;
            }
            return null;
        }

        /// <summary>
        /// Берем статы за день 7 дней назад, если таких нет но есть раньше берем их
        /// </summary>
        /// <param name="app"></param>
        /// <param name="parsigDay"></param>
        /// <param name="lastStat"></param>
        /// <returns></returns>
        private AppStat GetWeeklyStat(App app, DateTime parsigDay, AppStat lastStat)
        {
            if (parsigDay.Date.AddDays(-7) > lastStat.ParsingDate.Date) // есть статы на день раньше данного дня
            {
                var stats = app.AppStats
                    .Where(s => s.ParsingDate <= parsigDay.AddDays(-7)) //берем прошлый день или раньше
                    .OrderByDescending(s => s.ParsingDate);
                    
                var posStat = stats.Where(s => s.Position != -1).FirstOrDefault();
                if (posStat == null)
                {
                    return stats.FirstOrDefault();
                }
                return posStat;
            }
            return null;
        }

        /// <summary>
        /// Берем статы за день 30 дней назад, если таких нет но есть раньше берем их
        /// </summary>
        /// <param name="app"></param>
        /// <param name="parsigDay"></param>
        /// <param name="lastStat"></param>
        /// <returns></returns>
        private AppStat GetMonthlyStat(App app, DateTime parsigDay, AppStat lastStat)
        {
            if (parsigDay.Date.AddDays(-30) > lastStat.ParsingDate.Date) // есть статы на день раньше данного дня
            {
                var stats = app.AppStats
                    .Where(s => s.ParsingDate <= parsigDay.AddDays(-30)) //берем прошлый день или раньше
                    .OrderByDescending(s => s.ParsingDate);
                var posStat = stats.Where(s => s.Position != -1).FirstOrDefault();
                if (posStat == null)
                {
                    return stats.FirstOrDefault();
                }
                return posStat;
            }
            return null;
        }
    }
}
